#ifndef ads_globalsH
#define ads_globalsH
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
** 
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
** 
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
** 
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/


//============================================================================
/// \file   ads_globals.h
/// \author Uwe Kindler
/// \date   24.02.2017
/// \brief  Declaration of
//============================================================================


//============================================================================
//                                   INCLUDES
//============================================================================
#include <QPair>
#include <QtCore/QtGlobal>
#include <QPixmap>
#include <QWidget>
#include <QDebug>
#include <QStyle>
#include <QMouseEvent>

#include <iostream>

#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
#include <xcb/xcb.h>
#endif

QT_FORWARD_DECLARE_CLASS(QAbstractButton)

#ifndef ADS_STATIC
#ifdef ADS_SHARED_EXPORT
#define ADS_EXPORT Q_DECL_EXPORT
#else
#define ADS_EXPORT Q_DECL_IMPORT
#endif
#else
#define ADS_EXPORT
#endif
// 定义ADS_DEBUG_PRINT以启用大量调试输出
#ifdef ADS_DEBUG_PRINT
#define ADS_PRINT(s) qDebug() << s
#else
#define ADS_PRINT(s)
#endif

// 设置ADS_DEBUG_LEVEL以启用额外的调试输出和在布局更改后将布局转储到qDebug和std::cout中
#define ADS_DEBUG_LEVEL 0

// 前向声明QSplitter类
QT_FORWARD_DECLARE_CLASS(QSplitter)

// ads命名空间
namespace ads
{
    // 定义CDockSplitter类的前向声明
    class CDockSplitter;

    // DockWidgetArea枚举
    enum DockWidgetArea
    {
        NoDockWidgetArea = 0x00,
        LeftDockWidgetArea = 0x01,
        RightDockWidgetArea = 0x02,
        TopDockWidgetArea = 0x04,
        BottomDockWidgetArea = 0x08,
        CenterDockWidgetArea = 0x10,
        LeftAutoHideArea = 0x20,
        RightAutoHideArea = 0x40,
        TopAutoHideArea = 0x80,
        BottomAutoHideArea = 0x100,
        InvalidDockWidgetArea = NoDockWidgetArea,
        OuterDockAreas = TopDockWidgetArea | LeftDockWidgetArea | RightDockWidgetArea | BottomDockWidgetArea,
        AutoHideDockAreas = LeftAutoHideArea | RightAutoHideArea | TopAutoHideArea | BottomAutoHideArea,
        AllDockAreas = OuterDockAreas | CenterDockWidgetArea
    };

    // DockWidgetAreas标志
    Q_DECLARE_FLAGS(DockWidgetAreas, DockWidgetArea)

    // eTabIndex枚举
    enum eTabIndex
    {
        TabDefaultInsertIndex = -1,
        TabInvalidIndex = -2
    };

    // TitleBarButton枚举
    enum TitleBarButton
    {
        TitleBarButtonTabsMenu,
        TitleBarButtonUndock,
        TitleBarButtonClose,
        TitleBarButtonAutoHide
    };

    /**
     * 不同的拖动状态
     */
    enum eDragState
    {
        DraggingInactive,     //!< DraggingInactive
        DraggingMousePressed, //!< DraggingMousePressed
        DraggingTab,          //!< DraggingTab
        DraggingFloatingWidget//!< DraggingFloatingWidget
    };

    /**
     * UI中使用的不同图标
     */
    enum eIcon
    {
        TabCloseIcon,      //!< TabCloseIcon
        AutoHideIcon,      //!< AutoHideIcon
        DockAreaMenuIcon,  //!< DockAreaMenuIcon
        DockAreaUndockIcon,//!< DockAreaUndockIcon
        DockAreaCloseIcon, //!< DockAreaCloseIcon
        IconCount,         //!< just a delimiter for range checks
    };

    /**
     * 用于对dock wdget功能进行按位组合
     */
    enum eBitwiseOperator
    {
        BitwiseAnd,
        BitwiseOr
    };

    /**
     * 每个dock容器支持4个边栏
     */
    enum SideBarLocation
    {
        SideBarTop,
        SideBarLeft,
        SideBarRight,
        SideBarBottom,
        SideBarNone
    };

    // SideBarLocation枚举注册
    Q_ENUMS(SideBarLocation);

    namespace internal
    {
        // 恢复测试标志
        static const bool RestoreTesting = true;
        // 恢复标志
        static const bool Restore = false;
        // 关闭属性
        static const char* const ClosedProperty = "close";
        // 脏属性
        static const char* const DirtyProperty = "dirty";
        // 浮动小部件拖动开始事件
        extern const int FloatingWidgetDragStartEvent;
        // 停靠小部件拖动开始事件
        extern const int DockedWidgetDragStartEvent;

#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
        // 与X服务器直接通信的实用程序
        /**
         * 从缓存中获取原子或从XServer请求原子
         */
        xcb_atom_t xcb_get_atom(const char *name);

        /**
         * 将属性添加到窗口。仅适用于“隐藏”窗口。
         */
        void xcb_add_prop(bool state, WId window, const char *type, const char *prop);

        /**
         * 更新最多两个窗口属性。可以在可见窗口上设置。
         */
        void xcb_update_prop(bool set, WId window, const char *type, const char *prop, const char *prop2 = nullptr);

        /**
         * 仅用于调试目的。
         */
        bool xcb_dump_props(WId window, const char *type);

        /**
         * 从X11服务器获取活动窗口管理器。
         * 需要符合EWMH的窗口管理器（几乎所有常用的窗口管理器都符合）。
         * 否则返回“UNKNOWN”。
         */
        QString windowManager();
#endif

        /**
         * 用To小部件替换给定分隔器中的From小部件
         */
        void replaceSplitterWidget(QSplitter* Splitter, QWidget* From, QWidget* To);

        /**
         * 此函数向上遍历分隔器树以隐藏所有没有可见内容的分隔器
         */
        void hideEmptyParentSplitters(CDockSplitter* FirstParentSplitter);

        /**
         * QPair的便利类，提供比first和second更好的命名
         */
        class CDockInsertParam : public QPair<Qt::Orientation, bool>
        {
        public:
            using QPair<Qt::Orientation, bool>::QPair;
            Qt::Orientation orientation() const {return this->first;}
            bool append() const {return this->second;}
            int insertOffset() const {return append() ? 1 : 0;}
        };

        /**
         * 返回给定dock区域的插入参数
         */
        CDockInsertParam dockAreaInsertParameters(DockWidgetArea Area);

        /**
         * 返回AutoHide dock小部件区域的SieBarLocation
         */
        SideBarLocation toSideBarLocation(DockWidgetArea Area);

        /**
         * 对于顶部或底部边栏返回true，对于左侧和右侧边栏返回false
         */
        bool isHorizontalSideBarLocation(SideBarLocation Location);

        /**
         * 如果给定的dock区域是边栏区域，则返回true
         */
        bool isSideBarArea(DockWidgetArea Area);

/**
 * 搜索给定类型的父窗口部件。
 * 返回给定窗口部件的父窗口部件，如果窗口部件不是任何类型为T的窗口部件的子窗口部件，则返回0。
 *
 * 在CDockWidget中使用此函数是不安全的，因为只有当前停靠窗口有一个父窗口。在停靠区中不是当前停靠窗口的所有停靠窗口都没有父窗口。
 */
        template <class T>
        T findParent(const QWidget* w)
        {
            QWidget* parentWidget = w->parentWidget();
            while (parentWidget)
            {
                T ParentImpl = qobject_cast<T>(parentWidget);
                if (ParentImpl)
                {
                    return ParentImpl;
                }
                parentWidget = parentWidget->parentWidget();
            }
            return 0;
        }

/**
 * 根据给定的pixmap Source创建一个半透明的pixmap。
 * Opacity参数定义了从完全透明（0.0）到完全不透明（1.0）的不透明度。
 */
        QPixmap createTransparentPixmap(const QPixmap& Source, qreal Opacity);

/**
 * 在QFlags实例中设置标志的辅助函数。
 */
        template <class T>
        void setFlag(T& Flags, typename T::enum_type flag, bool on = true)
        {
#if QT_VERSION >= 0x050700
            Flags.setFlag(flag, on);
#else
            if(on)
            {
                Flags |= flag;
            }
            else
            {
                Flags &= ~flag;
            }
#endif
        }

/**
 * 在不混淆代码的情况下设置工具提示的辅助函数。
 */
        template <class QObjectPtr>
        void setToolTip(QObjectPtr obj, const QString &tip)
        {
#ifndef QT_NO_TOOLTIP
            obj->setToolTip(tip);
#else
            Q_UNUSED(obj);
	Q_UNUSED(tip);
#endif
        }

/**
 * 在Qt5和之后版本中访问鼠标事件全局位置的辅助函数。
 */
        inline QPoint globalPositionOf(QMouseEvent* ev)
        {
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
            return ev->globalPosition().toPoint();
#else
            return ev->globalPos();
#endif
        }

/**
 * 设置特定按钮的图标的辅助函数。
 * 使用此函数设置停靠区和停靠窗口按钮的图标。
 * 该函数首先使用CustomIconId从CIconProvider获取一个图标。
 * 如果IconProvider没有返回有效的图标（图标为空），则从QStyle中获取给定的标准pixmap。
 * param[in] Button 要设置图标的按钮
 * param[in] StandardPixmap 要用于按钮的标准pixmap
 * param[in] CustomIconId 自定义图标的标识符。
 */
        void setButtonIcon(QAbstractButton* Button, QStyle::StandardPixmap StandarPixmap,
        ads::eIcon CustomIconId);

        enum eRepolishChildOptions
        {
            RepolishIgnoreChildren,
            RepolishDirectChildren,
            RepolishChildrenRecursively
        };

/**
 * 调用给定窗口部件的样式的unpolish() / polish()来更新样式表，以便在属性更改时更新。
 */
        void repolishStyle(QWidget* w, eRepolishChildOptions Options = RepolishIgnoreChildren);

/**
 * 返回给定窗口部件在全局空间中的几何形状
 */
        QRect globalGeometry(QWidget* w);
    } // namespace internal
} // namespace ads

Q_DECLARE_OPERATORS_FOR_FLAGS(ads::DockWidgetAreas)

//---------------------------------------------------------------------------
#endif // ads_globalsH
